package win.larryzeal.jmx.mbean.advance;

import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by 张少昆 on 2017/8/21 0021.
 */
public class TrackingThreadPool extends ThreadPoolExecutor {
	private final Map<Runnable, Boolean> inProgress = new ConcurrentHashMap<Runnable, Boolean>();
	private final ThreadLocal<Long> startTime = new ThreadLocal<Long>();
	private long totalTime;
	private int totalTasks;

	public TrackingThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime,
							  TimeUnit unit, BlockingQueue<Runnable> workQueue){
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
	}

	/**
	 * 在执行之前，由thread调用？
	 * Method invoked prior to executing the given Runnable in the given thread.
	 * This method is invoked by thread t that will execute task r, and may be used to re-initialize ThreadLocals, or to perform logging.
	 * Note: To properly nest multiple overridings, subclasses should generally invoke super.beforeExecute at the end of this method.
	 *
	 * @param t
	 * @param r
	 */
	protected void beforeExecute(Thread t, Runnable r){
		inProgress.put(r, Boolean.TRUE);
		startTime.set(new Long(System.currentTimeMillis()));
		super.beforeExecute(t, r); // 似乎应该放到本方法的末尾处
	}

	/**
	 * 在执行之后。
	 * Method invoked upon completion of execution of the given Runnable. This method is invoked by the thread that executed the task.
	 * If non-null, the Throwable is the uncaught RuntimeException or Error that caused execution to terminate abruptly.
	 * Note: To properly nest multiple overridings, subclasses should generally invoke super.afterExecute at the beginning of this method.
	 *
	 * @param r
	 * @param t
	 */
	protected void afterExecute(Runnable r, Throwable t){
		long time = System.currentTimeMillis() - startTime.get().longValue();//获取执行时间
		synchronized(this){
			totalTime += time;
			++totalTasks;
		}
		inProgress.remove(r);
		super.afterExecute(r, t);
	}

	public Set<Runnable> getInProgressTasks(){ // 为毛不需要同步？因为是ConcurrentHashMap
		return Collections.unmodifiableSet(inProgress.keySet());
	}

	public synchronized int getTotalTasks(){ // 这个就同步了
		return totalTasks;
	}

	public synchronized double getAverageTaskTime(){
		return (totalTasks == 0) ? 0 : totalTime / totalTasks;
	}
}